package compiler

import (
	"io/ioutil"
	"encoding/json"
	"kumachan/standalone/util/richtext"
	"kumachan/lang/source"
	"kumachan/lang/typsys"
	"kumachan/lang/textual/ast"
	"kumachan/interpreter/program"
)


type Project struct {
	ProjectFiles     [] string
	DependencyFiles  [] string
}
func LoadProject(path string) (Project, error) {
	// TODO: load standalone script, error on invalid suffix
	var content, err = ioutil.ReadFile(path)
	if err != nil { return Project{}, err }
	var project Project
	{ var err = json.Unmarshal(content, &project)
	if err != nil { return Project{}, err }
	return project, nil }
}

func Compile(project Project, fs FileSystem, meta program.Metadata) (*program.Program, *NsHeaderMap, *Executable, richtext.Errors, source.Errors) {
	// TODO: handle dependencies
	var ldr_errs = new(richtext.Errors)
	var chk_errs = new(source.Errors)
	var hdr_list = make([] *Header, 0)
	var impl_list = make([] *Impl, 0)
	var load = func(name string, fs FileSystem) {
		var root, err = Load(name, fs)
		if err == nil {
			var hdr, impl = analyze(root, chk_errs)
			hdr_list = append(hdr_list, hdr)
			impl_list = append(impl_list, impl)
		} else {
			richtext.ErrorsJoin(ldr_errs, err)
		}
	}
	load(Builtin())
	for _, name := range project.ProjectFiles {
		load(name, fs)
	}
	var ctx = groupHeaders(hdr_list, chk_errs)
	var fragments = make([] *Fragment, 0)
	for _, hdr := range hdr_list {
		checkHeader(hdr, ctx, chk_errs)
	}
	for i := range hdr_list {
		var hdr = hdr_list[i]
		var impl = impl_list[i]
		var fragment = checkImpl(impl, hdr, ctx, chk_errs)
		fragments = append(fragments, fragment)
	}
	var exe = link(fragments)
	var p = &program.Program {
		Metadata:   meta,
		Executable: exe,
	}
	return p, ctx, exe, *ldr_errs, *chk_errs
}
func CompileExpr(node ast.Expr, ctx *NsHeaderMap, exe *Executable, bindings ([] *program.Binding), ns string, expected typsys.Type) (*program.Expr, *source.Error) {
	var fd = makeFragmentDraft(ns)
	var ec = createExprContext(nil, fd, ctx)
	for _, b := range bindings {
		ec.addBinding(b)
	}
	var cc = createExprCheckContext(expected, ec)
	var expr, err = checkExpr(node, cc)
	if err != nil { return nil, err }
	var fragment = fd.content
	linkFragment(exe, fragment)
	return expr, nil
}


